/*
 * Licensed to the 南京汇海交通科技有限公司
 *
 * Copyright (c) 2025.
 * All rights reserved.
 *
 * 本软件属南京汇海交通科技有限公司所有，在未获得南京汇海交通科技有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.chframework.boot.web.reactor;

import com.chframework.boot.core.response.result.ApiResult;
import com.chframework.boot.core.response.status.ApiStatusEnum;
import com.chframework.common.exception.ApplicationException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.pattern.PathPattern;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

// 特别说明：
// - 添加`@Controller`注解是为了使切面能够拦截到`/path/list`的请求。
// - 为避免冲突，禁止FluxPathController再被`@ComponentScan`扫描到，它在SpringWebFluxAutoConfiguration中已经被显式声明为java bean。
@Controller
@RequestMapping("/project")
public class FluxPathController {

    private final RequestMappingHandlerMapping requestMappingHandlerMapping;

    public FluxPathController(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
    }

    /**
     * 获取 spring-webflux工程中所有的Api-Path列表
     */
    @ResponseBody
    @RequestMapping("/path/list")
    public Mono<ApiResult<TreeMap<String, List<String>>>> readApiList() {
        return ApiResult.<TreeMap<String, List<String>>>create()
                .map(result -> result
                        .setStatus(ApiStatusEnum.SUCCESS)
                        .setResult(requestMappingHandlerMapping.getHandlerMethods()
                                .entrySet()
                                .parallelStream()
                                .collect(Collectors.toMap(
                                        entry -> entry.getValue().getMethod().toGenericString(),
                                        entry -> entry.getKey()
                                                .getPatternsCondition()
                                                .getPatterns()
                                                .parallelStream()
                                                .map(PathPattern::getPatternString)
                                                .collect(Collectors.toList()),
                                        (oldValue, newValue) -> newValue,
                                        TreeMap::new
                                        )
                                )
                        )
                )
                .onErrorResume(e -> Mono.error(new ApplicationException(e)));
    }

}
